package edu.bbu.commonproject.desktop.gui.view.swing.file.traffic;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

import edu.bbu.commonproject.desktop.client.utils.FileTransferObserver;
import edu.bbu.commonproject.desktop.gui.view.swing.file.traffic.utils.ListContainer;
import edu.bbu.commonproject.desktop.gui.view.swing.file.traffic.utils.Separator;
import edu.bbu.commonproject.desktop.gui.view.swing.utils.Design;
import edu.bbu.commonproject.desktop.gui.view.swing.utils.TexturedPanel;

/**
 * The list item.
 */
public class ListItem extends TexturedPanel implements FileTransferObserver
{	
	/** The status. */
	private int status;
	
	/** The recent status. */
	private int recentStatus;
	
	/** The list container. */
	private ListContainer listContainer;
	
	/** It inicilises the file size. */
	private long fileSize = 0;
	
	/** The file name label. */
	private JLabel fileNameLabel;
	
	/** The file size label. */
	private JLabel fileSizeLabel;
	
	/** The status image label. */
	private JLabel statusImageLabel;
	
	/** The A separator label. */
	private Separator sepatatorALabel;
	
	/** The B separator label. */
	private Separator sepatatorBLabel;
	
	/** The C separator label. */
	private Separator sepatatorCLabel;
	
	/** The progress bar. */
	private JProgressBar progressBar;
	
	/**
	 * The constructor.
	 * @param status the status.
	 */
	public ListItem(int status)
	{	
		this.status = status;
		
		fileNameLabel = new JLabel();
		fileNameLabel.setPreferredSize(new Dimension(200, 20));
		
		fileSizeLabel = new JLabel("B");
		fileSizeLabel.setHorizontalAlignment(JLabel.CENTER);
		fileSizeLabel.setPreferredSize(new Dimension(50, 20));
		
		statusImageLabel = new JLabel();
		setStatusIcon();
		
		progressBar = new JProgressBar(0, 100);
		progressBar.setValue(0);
		progressBar.setStringPainted(true);
		
		sepatatorALabel = new Separator();
		sepatatorBLabel = new Separator();
		sepatatorCLabel = new Separator();
		
		this.setUnselectedTexture();
		this.setOpaque(false);
		this.setLayout(new GridBagLayout());
		this.setPreferredSize(new Dimension(500, 30));
		
		this.addMouseListener(new MouseAdapter()
		{
			public void mousePressed(MouseEvent e)
			{
				setNewSelectedObject();
			}
		});
		
		
		GridBagConstraints gridBagConstraints = new GridBagConstraints();
		
		gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
		
		gridBagConstraints.weightx = 0;
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 0;
		this.add(statusImageLabel, gridBagConstraints);
		
		gridBagConstraints.weightx = 0;
		gridBagConstraints.gridx = 1;
		gridBagConstraints.gridy = 0;
		this.add(sepatatorALabel, gridBagConstraints);
		
		gridBagConstraints.weightx = 0.02;
		gridBagConstraints.gridx = 2;
		gridBagConstraints.gridy = 0;
		this.add(fileNameLabel, gridBagConstraints);
		
		gridBagConstraints.weightx = 0;
		gridBagConstraints.gridx = 3;
		gridBagConstraints.gridy = 0;
		this.add(sepatatorBLabel, gridBagConstraints);
		
		gridBagConstraints.weightx = 0.02;
		gridBagConstraints.gridx = 4;
		gridBagConstraints.gridy = 0;
		this.add(fileSizeLabel, gridBagConstraints);
		
		gridBagConstraints.weightx = 0;
		gridBagConstraints.gridx = 5;
		gridBagConstraints.gridy = 0;
		this.add(sepatatorCLabel, gridBagConstraints);
		
		gridBagConstraints.weightx = 0.5;
		gridBagConstraints.gridx = 6;
		gridBagConstraints.gridy = 0;
		this.add(progressBar, gridBagConstraints);		
	}
	
	/**
	 * Sets the lsit container.
	 * @param listContainer the lsit container.
	 */
	public void setListContainer(ListContainer listContainer)
	{
		this.listContainer = listContainer;
	}
	
	/**
	 * Gets the list container.
	 * @return the list container.
	 */
	public ListContainer getListContainer()
	{
		return listContainer;
	}
	
	/**
	 * Sets the file name.
	 */
	public void setFileName(final String fileName)
	{
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				fileNameLabel.setText(fileName);
				repaint();
			}
		});
	}
	
	/**
	 * Gets the file name.
	 */
	public String getFileName()
	{
		return fileNameLabel.getText();
	}
	
	/**
	 * The readeble file size.
	 * @param size the file size.
	 * @return the file size in decimal format.
	 */
	public String readableFileSize(long size) 
	{
		if (size <= 0)
		{
			return "0";
		}
		
		String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
		int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
		
		return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
	}

	/**
	 * Sets the file size.
	 */
	public void setFileSize(long fileSize) 
	{
		this.fileSize = fileSize;
		final String fileSizeString = readableFileSize(fileSize);	
		
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				fileSizeLabel.setText(fileSizeString);
				repaint();
			}
		});
	}
	
	/**
	 * Gets the file size.
	 */
	public long getFileSize()
	{
		return fileSize;
	}
	
	/**
	 * Sets the progress percent.
	 */
	public void setProgressPercent(final int percent)
	{
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				progressBar.setValue(percent);
				repaint();
			}
		});
	}
	
	/**
	 * Gets the progress percent.
	 */
	public int getProgressPercent()
	{
		return progressBar.getValue();
	}
	
	/**
	 * Sets the status.
	 */
	public void setStatus(int status)
	{
		this.status = status;
		setStatusIcon();
		listContainer.reorderElements();
	}
	
	/**
	 * Gets the status.
	 */
	public int getStatus()
	{
		return status;
	}
	
	/**
	 * Sets the icon status.
	 */
	private void setStatusIcon()
	{
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				switch (status)
				{
					case DOWNLOAD:
					{
						statusImageLabel.setIcon(new ImageIcon(Design.TRAFFIC_STATUS_DOWNLOAD));
						
					}break;
					
					case UPLOAD:
					{
						statusImageLabel.setIcon(new ImageIcon(Design.TRAFFIC_STATUS_UPLOAD));
						
					}break;
					
					case FINISHED:
					{
						statusImageLabel.setIcon(new ImageIcon(Design.TRAFFIC_STATUS_FINISHED));
						
					}break;
					
					case PAUSED:
					{
						statusImageLabel.setIcon(new ImageIcon(Design.TRAFFIC_STATUS_PAUSED));
						
					}break;
					
					case STOPPED:
					{
						statusImageLabel.setIcon(new ImageIcon(Design.TRAFFIC_STATUS_STOPPED));
						
					}break;
					
					case CRASHED:
					{
						statusImageLabel.setIcon(new ImageIcon(Design.TRAFFIC_STATUS_CRASHED));
						
					}break;
				}
				
				repaint();
			}
		});
	}
			
	/**
	 * Sets the selected texture.
	 */
	public void setSelectedTexture()
	{
		this.setTexture(Design.TRAFFIC_COMPONENT_SELECTED);
		repaint();
	}
	
	/**
	 * Sets the unselected texture.
	 */
	public void setUnselectedTexture()
	{
		this.setTexture(Design.TRAFFIC_COMPONENT_ITEM);
		repaint();
	}
	
	/**
	 * Sets the selected object.
	 */
	private void setNewSelectedObject()
	{
		if(listContainer != null)
		{
			if(listContainer.getSelectedObject() != null)
			{
				listContainer.getSelectedObject().setUnselectedTexture();
			}
			
			listContainer.setSelectedObject(this);
			setSelectedTexture();
		}
	}

	/**
	 * It will start the transfer.
	 */
	public synchronized void startTransfer()
	{
		if(status == PAUSED)
		{
			setStatus(recentStatus);
			this.notify();
		}
	}

	/**
	 * It will pause the transfer.
	 */
	public synchronized void pauseTransfer()
	{
		if(status == UPLOAD || status == DOWNLOAD)
		{
			recentStatus = status;
			setStatus(PAUSED);
		}
	}

	/**
	 * It will stop the transfer.
	 */
	public synchronized void stopTransfer()
	{
		if(status == UPLOAD || status == DOWNLOAD)
		{
			setStatus(STOPPED);
		}
		else if(status == PAUSED)
		{
			setStatus(STOPPED);
			this.notify();
		}
	}
}
